//
//  AFStackDictionary.m
//  Amber
//
//  Created by Keith Duncan on 28/01/2009.
//  Copyright 2009 thirty-three software. All rights reserved.
//

#import "AFStackDictionary.h"

@interface AFStackDictionary ()
@property (retain) NSPointerArray *keys, *objects;
@end

@interface AFStackDictionary (Private)
- (void)_assertExternalOperationValid;
@end

@implementation AFStackDictionary

@synthesize keys=_keys, objects=_objects;

- (id)init {
	self = [super init];
	if (self == nil) return nil;
	
	self.keys = [NSPointerArray pointerArrayWithStrongObjects];
	self.objects = [NSPointerArray pointerArrayWithStrongObjects];
	
	return self;
}

- (void)dealloc {
	self.keys = nil;
	self.objects = nil;
	
	[super dealloc];
}

- (NSUInteger)count; {
	return [self.keys count];
}

- (id)objectForKey:(id)key; {
	NSUInteger index = [[self.keys allObjects] indexOfObject:key];
	return (index == NSNotFound) ? nil : [self.objects pointerAtIndex:index];
}

- (void)removeObjectForKey:(id)key {
	NSUInteger index = [[self.keys allObjects] indexOfObject:key];
	if (index == NSNotFound) return;
	
	[self.keys removePointerAtIndex:index];
	[self.keys compact];
	
	[self.objects removePointerAtIndex:index];
	[self.objects compact];
}

- (void)setObject:(id)object forKey:(id)key {
	[self _assertExternalOperationValid];
	
	[self pushKey:key];
	[self addObject:object];
}

- (void)_pushObject:(id)object array:(NSPointerArray *)array {
	if ((([self.keys count]+(array == self.keys ? 1 : 0)) != ([self.objects count]+ (array == self.objects ? 1 : 0))) && (([self.keys count]+1) != ([self.objects count]+1))) {
		[NSException raise:NSInternalInconsistencyException format:@"%s, cannot add another object to %p, key-value pairs will become out of sync.", __PRETTY_FUNCTION__, array, nil];
		return;
	}
	
	[array addPointer:object];
}

- (void)pushKey:(id <NSCopying>)key; {
	[self _pushObject:[[key copyWithZone:NULL] autorelease] array:self.keys];
}

- (void)addObject:(id)object; {
	[self _pushObject:object array:self.objects];
}

- (NSEnumerator *)keyEnumerator; {
	[self _assertExternalOperationValid];
	
	return [[self.keys allObjects] objectEnumerator];
}

@end

@implementation AFStackDictionary (Private)

- (void)_assertExternalOperationValid {
	if ([self.keys count] == [self.objects count]) return;
	[NSException raise:NSInternalInconsistencyException format:@"%s, in the middle of a key/object push operation, cannot %s, behaviour undefined", __PRETTY_FUNCTION__, sel_getName(_cmd), nil];
}

@end
